package com.snopy.concurrency.atomic;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author snopy
 * @version 1.0.0
 * @classname AtomicReferenceDemo
 * @description
 * @email 77912204@qq.com
 * @date 2022/06/28 14:16
 */
public class AtomicReferenceDemo {
    public static void main(String[] args) {
        AtomicAccount atomicAccount = new AtomicAccount(10000);
        Account.trade(atomicAccount);
    }

}
class AtomicAccount implements Account{
    public AtomicAccount(Integer balance) {
        this.balance = new AtomicReference<>(new BigDecimal(balance));
    }

    private AtomicReference<BigDecimal> balance;


    @Override
    public BigDecimal getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(BigDecimal amount) {
        while (true){
            BigDecimal prev = balance.get();
            BigDecimal next = prev.subtract(amount);
            if (balance.compareAndSet(prev,next)) {
                break;
            }
        }
    }
}
interface Account{
    BigDecimal getBalance();
    void withdraw(BigDecimal amount);
    static void trade(Account account){
        List<Thread> ts = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(()->{
                account.withdraw(new BigDecimal(10));
            }));
        }
        long start = System.currentTimeMillis();
        ts.forEach(Thread::start);
        ts.forEach(t->{
            try{
                t.join();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        });
        long end = System.currentTimeMillis();
        System.out.println(account.getBalance()+" cost:"+(end-start));
    }
}
